package mqtt

import (
	"encoding/json"
	"errors"
	"gitee.com/fierce_wolf/go-fox-edge-common/commMqtt"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Json"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Method"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/String"
	"gitee.com/fierce_wolf/go-fox-edge-common/httpserver"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"go-fox-edge-kernel-manager/restfullike/vo"
	"net/http"
	"strings"
)

type mqttHandler struct {
	clientId string
	topic    string
	router   map[string]interface{}
}
type mqttCtx struct {
	uri    string
	params map[string]string
}

func (e *mqttHandler) Handler() mqtt.MessageHandler {
	return func(client mqtt.Client, msg mqtt.Message) {
		requestVO := vo.Type.RestfulLikeRequestVO.New()

		// 解码JSON
		err := json.Unmarshal(msg.Payload(), requestVO)
		if err != nil {
			return
		}
		requestVO.Topic = msg.Topic()

		// 执行请求
		result, err := e.execute(requestVO)

		// 响应请求
		e.respond(requestVO, result, err)
	}
}

func (e *mqttHandler) execute(requestVO *vo.RestfulLikeRequestVO) (rtn interface{}, err error) {
	// 定义一个函数级的异常拦截，用来防止可能的代码BUG
	defer func() {
		if r := recover(); r != nil {
			rtn = nil
			err = errors.New(String.ToString(r))
		}
	}()

	if Method.HasEmpty(requestVO.Method, requestVO.Resource, requestVO.Uuid) {
		return nil, errors.New("参数缺失：uuid, resource, method")
	}

	key := e.getRes(requestVO.Resource) + ":" + strings.ToUpper(requestVO.Method)
	handler := e.router[key]
	if handler == nil {
		return nil, errors.New("尚未支持的方法")
	}

	// 获取函数类型的反射类型和函数类型
	if fun, ok := handler.(httpserver.HandlerGet); ok {
		ctx := mqttCtx{}
		ctx.uri = requestVO.Resource
		ctx.build()
		return ctx.doGet(fun)
	}
	if fun, ok := handler.(httpserver.HandlerDel); ok {
		ctx := mqttCtx{}
		ctx.uri = requestVO.Resource
		ctx.build()
		return ctx.doDel(fun)
	}
	if fun, ok := handler.(httpserver.HandlerPost); ok {
		param := requestVO.Body.(map[string]interface{})
		return fun(nil, param)
	}
	if fun, ok := handler.(httpserver.HandlerPut); ok {
		param := requestVO.Body.(map[string]interface{})
		return fun(nil, param)
	}

	return nil, errors.New("内部出现异常")
}

func (e *mqttHandler) getRes(resource string) string {
	idx := strings.IndexAny(resource, "?")
	if idx < 0 {
		return resource
	}

	return resource[:idx]
}

func (e *mqttHandler) respond(requestVO *vo.RestfulLikeRequestVO, data interface{}, err error) {
	client := commMqtt.GetClient(e.clientId)
	if client == nil {
		return
	}

	respondVO := vo.Type.RestfulLikeRespondVO.New()
	respondVO.BindRequestVO(requestVO)

	if err != nil {
		respondVO.Code = http.StatusInternalServerError
		respondVO.Msg = err.Error()
	} else {
		respondVO.Code = http.StatusOK
		respondVO.Body = data
	}

	client.Publish(e.topic, Json.BuildJson(respondVO), 10*1000)
}

func (e *mqttCtx) doGet(handler httpserver.HandlerGet) (interface{}, error) {
	return handler(e)
}

func (e *mqttCtx) doDel(handler httpserver.HandlerDel) (interface{}, error) {
	return handler(e)
}

func (e *mqttCtx) build() {
	e.params = make(map[string]string)
	idx := strings.IndexAny(e.uri, "?")
	if idx < 0 {
		return
	}

	param := e.uri[idx+1:]
	items := strings.Split(param, "&")
	if len(items) == 0 {
		return
	}

	for _, item := range items {
		data := strings.Split(item, "=")
		if len(data) != 2 {
			continue
		}

		e.params[data[0]] = data[1]
	}
}

func (e *mqttCtx) Query(key string) string {
	if len(e.params) == 0 {
		return ""
	}

	return e.params[key]
}
